#!/usr/bin/env node

/**
 * Run Tests Script
 * Command-line interface for the unified test execution system
 * Usage: node scripts/run-tests.js [options] [test-types...]
 */

const { TestCoordinator, TestConfigValidator } = require('./test-all');
const path = require('path');

// Parse command line arguments
const args = process.argv.slice(2);
const options = {};
const testTypes = [];

let currentOption = null;
for (const arg of args) {
  if (arg.startsWith('--')) {
    currentOption = arg.slice(2);
    if (currentOption === 'help' || currentOption === 'h') {
      showUsage();
      process.exit(0);
    }
  } else if (currentOption) {
    // Convert argument to appropriate type
    if (['timeout', 'retries'].includes(currentOption)) {
      options[currentOption] = parseInt(arg, 10);
    } else if (['parallel', 'coverage', 'merge-coverage', 'verbose'].includes(currentOption)) {
      options[currentOption] = arg === 'true';
    } else {
      options[currentOption] = arg;
    }
    currentOption = null;
  } else {
    testTypes.push(arg);
  }
}

// Default to all test types if none specified
if (testTypes.length === 0) {
  testTypes.push('unit', 'integration', 'mcp');
}

/**
 * Show usage information
 */
function showUsage() {
  console.log(`
Vision Analyzer Test Runner

USAGE:
  node scripts/run-tests.js [options] [test-types...]

TEST TYPES:
  unit         Run unit tests only
  integration  Run integration tests only
  mcp          Run MCP tests only
  (default)    Run all test types

OPTIONS:
  --help, -h              Show this help message
  --timeout <ms>          Test timeout in milliseconds (default: 120000)
  --parallel <true|false> Run tests in parallel (default: true)
  --retries <count>       Number of retries for failed tests (default: 0)
  --coverage <true|false> Collect coverage (default: false)
  --merge-coverage <true|false> Merge coverage reports (default: false)
  --verbose <true|false>  Verbose output (default: false)

EXAMPLES:
  node scripts/run-tests.js                    # Run all tests
  node scripts/run-tests.js unit               # Run unit tests only
  node scripts/run-tests.js unit integration   # Run unit and integration tests
  node scripts/run-tests.js --coverage true    # Run all tests with coverage
  node scripts/run-tests.js --timeout 60000    # Run tests with 60s timeout
  node scripts/run-tests.js --parallel false   # Run tests sequentially
`);
}

/**
 * Main execution function
 */
async function main() {
  const startTime = Date.now();
  const projectRoot = process.cwd();

  console.log('='.repeat(60));
  console.log('           VISION ANALYZER TEST RUNNER');
  console.log('='.repeat(60));
  console.log(`Project: ${projectRoot}`);
  console.log(`Test Types: ${testTypes.join(', ')}`);
  console.log(`Options: ${JSON.stringify(options, null, 2)}`);
  console.log('');

  try {
    // Step 1: Validate configuration
    console.log('🔍 Validating test configuration...');
    const validator = new TestConfigValidator(projectRoot);
    const validation = validator.validateAll();

    if (!validation.valid) {
      console.log('❌ Configuration validation failed:');
      console.log(validator.generateValidationReport().report);
      process.exit(1);
    }

    console.log('✓ Configuration validation passed');
    console.log('');

    // Step 2: Create test coordinator
    console.log('🚀 Initializing test coordinator...');
    const coordinator = new TestCoordinator(options);

    // Step 3: Discover test suites
    console.log('📋 Discovering test suites...');
    const discoveryResults = {};
    for (const type of testTypes) {
      const suites = coordinator.discoverTestSuites(type);
      discoveryResults[type] = suites;
      console.log(`  ${type}: ${suites.length} test suites found`);
    }

    // Validate that we found tests
    const totalSuites = Object.values(discoveryResults).reduce((sum, suites) => sum + suites.length, 0);
    if (totalSuites === 0) {
      console.log('❌ No test suites found. Please check your test directory structure.');
      process.exit(1);
    }

    console.log(`✓ ${totalSuites} test suites discovered`);
    console.log('');

    // Step 4: Run tests
    console.log('🧪 Running tests...');
    let results;

    if (testTypes.length === 1) {
      // Run single test type
      results = [await coordinator.runTests(testTypes[0], options)];
    } else {
      // Run multiple test types
      if (options.parallel !== false) {
        console.log('Running tests in parallel...');
        results = await coordinator.runTestsParallel(testTypes, options);
      } else {
        console.log('Running tests sequentially...');
        results = await coordinator.runTestsSequential(testTypes, options);
      }
    }

    // Step 5: Generate report
    console.log('');
    console.log('📊 Generating test report...');
    const report = coordinator.generateReport(results);
    console.log(report);

    // Step 6: Calculate total duration
    const totalDuration = Date.now() - startTime;
    console.log(`Total execution time: ${(totalDuration / 1000).toFixed(2)}s`);

    // Step 7: Exit with appropriate code
    const failedTests = results.filter(r => !r.success);
    if (failedTests.length > 0) {
      console.log('');
      console.log(`❌ ${failedTests.length} test suite(s) failed`);
      process.exit(1);
    } else {
      console.log('');
      console.log('🎉 All tests passed!');
      process.exit(0);
    }

  } catch (error) {
    console.error('💥 Fatal error during test execution:');
    console.error(error.message);
    console.error(error.stack);
    process.exit(1);
  }
}

// Handle uncaught exceptions
process.on('uncaughtException', (error) => {
  console.error('💥 Uncaught exception:');
  console.error(error.message);
  process.exit(1);
});

process.on('unhandledRejection', (reason, promise) => {
  console.error('💥 Unhandled promise rejection:');
  console.error(reason);
  process.exit(1);
});

// Handle interrupt signals
process.on('SIGINT', () => {
  console.log('\\n🛑 Test execution interrupted by user');
  process.exit(130);
});

// Run main function
if (require.main === module) {
  main();
}

module.exports = { main };